#include "hd_dec_chip_spi.h"
#include "hc32_ddl.h"
#include "bsp_log.h"
#include "bsp_interrupt.h"
#include "bsp_dma.h"
#define SPI_UNIT                        (M4_SPI1)
#define SPI_UNIT_CLOCK                  (PWC_FCG1_PERIPH_SPI1)

#define SPI_DUMMY_BYTE_VALUE          (0xffu)

#define SPI_NSS_PORT                    (PortA)
#define SPI_NSS_PIN                     (Pin05)

#define SPI_NSS_HIGH()                  (PORT_SetBits(SPI_NSS_PORT, SPI_NSS_PIN))
#define SPI_NSS_LOW()                   (PORT_ResetBits(SPI_NSS_PORT, SPI_NSS_PIN))

#define SPI_SCK_PORT                    (PortA)
#define SPI_SCK_PIN                     (Pin04)
#define SPI_SCK_FUNC                    (Func_Spi1_Sck)

#define SPI_MISO_PORT                   (PortA)
#define SPI_MISO_PIN                    (Pin02)
#define SPI_MISO_FUNC                   (Func_Spi1_Miso)

#define SPI_MOSI_PORT                   (PortA)
#define SPI_MOSI_PIN                    (Pin03) 
#define SPI_MOSI_FUNC                   (Func_Spi1_Mosi)

#define SPI_DMA_UNIT                    (M4_DMA2)
#define SPI_DMA_CLOCK_UNIT              (PWC_FCG0_PERIPH_DMA2)
#define SPI_DMA_TX_CHANNEL              (DmaCh1)
#define SPI_DMA_RX_CAHNNEL              (DmaCh0)
#define SPI_DMA_TX_TRIG_SOURCE          (EVT_SPI1_SPTI)
#define SPI_DMA_RX_TRIG_SOURCE          (EVT_SPI1_SPRI)
#define SPI_DMA_RX_COMPLETE_SRC         (INT_DMA2_TC0)

static char u8DummyByte = 0xff;

uint8_t Spi_WriteReadByte(uint8_t u8Data)
{
    uint8_t u8Byte;

    /* Wait tx buffer empty */
    while (Reset == SPI_GetFlag(SPI_UNIT, SpiFlagSendBufferEmpty))
    {
    }
    /* Send data */
    SPI_SendData8(SPI_UNIT, u8Data);
    /* Wait rx buffer full */
    while (Reset == SPI_GetFlag(SPI_UNIT, SpiFlagReceiveBufferFull))
    {
    }
    /* Receive data */
    u8Byte = SPI_ReceiveData8(SPI_UNIT);

    return u8Byte;
}


bool write_dec_chip_reg(char command, char addr, char *pVal, int len) 
{
    LOG("enter, command = 0x%02x \r\n", command);

    uint16_t u16Index = 0u;

    SPI_NSS_LOW();
    Ddl_Delay1ms(100);

    Spi_WriteReadByte(command);    
    Spi_WriteReadByte(addr);
    while (len--)
    {
        Spi_WriteReadByte(pVal[u16Index]);
        u16Index++;
    }
    while (Reset == SPI_GetFlag(SPI_UNIT, SpiFlagSpiIdle))
    {
    }
    SPI_NSS_HIGH();

    LOG_INFO("exit \r\n");

    return true;
}
  
bool read_dec_chip_reg(char command, char addr, char *pVal, int len)
{
    LOG("enter, command = 0x%02x \r\n", command);

    uint16_t u16Index = 0u;

    SPI_NSS_LOW();
    Ddl_Delay1ms(100);

    Spi_WriteReadByte(command);    
    Spi_WriteReadByte(addr);
    while (len--)
    {
        pVal[u16Index] = Spi_WriteReadByte(SPI_DUMMY_BYTE_VALUE);
        u16Index++;
    }
    while (Reset == SPI_GetFlag(SPI_UNIT, SpiFlagSpiIdle))
    {
    }
    SPI_NSS_HIGH();

    LOG_INFO("exit \r\n");

    return true;
}


void hd_spi_init(E_CHIP_STAGE eStage){
    LOG_INFO("enter \r\n");

    stc_spi_init_t stcSpiInit;
    MEM_ZERO_STRUCT(stcSpiInit);

    stc_port_init_t stcPortInit;
    MEM_ZERO_STRUCT(stcPortInit);
    
    /* Configuration peripheral clock */
    PWC_Fcg1PeriphClockCmd(SPI_UNIT_CLOCK, Enable);

    stcPortInit.enPinMode = Pin_Mode_Out;
    stcPortInit.enPullUp = Enable;
    PORT_Init(SPI_NSS_PORT, SPI_NSS_PIN, &stcPortInit);
    
    /* Configuration SPI pin */
    PORT_SetFunc(SPI_SCK_PORT, SPI_SCK_PIN, SPI_SCK_FUNC, Disable);
    PORT_SetFunc(SPI_MOSI_PORT, SPI_MOSI_PIN, SPI_MOSI_FUNC, Disable);
    PORT_SetFunc(SPI_MISO_PORT, SPI_MISO_PIN, SPI_MISO_FUNC, Disable);
    PORT_SetFunc(SPI_NSS_PORT, SPI_NSS_PIN, Func_Spi1_Nss0, Disable);


    //输入时钟源频率为 84MHZ，32分频后SPI最大接收时钟频率为 2.625MHZ
    if (eStage == E_CHIP_WORK)
    {
        // 84/32 = 2.625MHZ
        stcSpiInit.enClkDiv = SpiClkDiv32;
    }
    else if (eStage == E_CHIP_START_UP)
    {
        // 84/128 = 0.65625MHZ
        stcSpiInit.enClkDiv = SpiClkDiv128;
    }

    stcSpiInit.enFrameNumber = SpiFrameNumber1;
    stcSpiInit.enDataLength = SpiDataLengthBit8;

    //分所FPGA调试透传图像，其先发送一个字节，发送的第一个bit为LSB
    stcSpiInit.enFirstBitPosition = SpiFirstBitPositionLSB;
    
    //SPI空闲时间 SCK为低电平
    stcSpiInit.enSckPolarity = SpiSckIdleLevelLow;

    //SPI相位，Odd（奇数） Even（偶数），SpiSckOddSampleEvenChange
    //平常时钟为低，第一个上长沿用Odd奇数表示，接着下一个下降沿用Even表示
    //CPOL = 0, CPHA = 0, 也就是上升沿采样、下降沿输出
    stcSpiInit.enSckPhase = SpiSckOddSampleEvenChange;

    stcSpiInit.enReadBufferObject = SpiReadReceiverBuffer;
    stcSpiInit.enWorkMode = SpiWorkMode4Line;
    stcSpiInit.enTransMode = SpiTransFullDuplex;
    stcSpiInit.enCommAutoSuspendEn = Disable;
    stcSpiInit.enModeFaultErrorDetectEn = Disable;
    stcSpiInit.enParitySelfDetectEn = Disable;
    stcSpiInit.enParityEn = Disable;
    stcSpiInit.enParity = SpiParityEven;

    stcSpiInit.enMasterSlaveMode = SpiModeMaster;
    stcSpiInit.stcDelayConfig.enSsSetupDelayOption = SpiSsSetupDelayCustomValue;
    stcSpiInit.stcDelayConfig.enSsSetupDelayTime = SpiSsSetupDelaySck1;
    stcSpiInit.stcDelayConfig.enSsHoldDelayOption = SpiSsHoldDelayCustomValue;
    stcSpiInit.stcDelayConfig.enSsHoldDelayTime = SpiSsHoldDelaySck1;
    stcSpiInit.stcDelayConfig.enSsIntervalTimeOption = SpiSsIntervalCustomValue;
    stcSpiInit.stcDelayConfig.enSsIntervalTime = SpiSsIntervalSck6PlusPck2;
    stcSpiInit.stcSsConfig.enSsValidBit = SpiSsValidChannel0;
    stcSpiInit.stcSsConfig.enSs0Polarity = SpiSsLowValid;

    SPI_Init(SPI_UNIT, &stcSpiInit);
    SPI_Cmd(SPI_UNIT, Enable);
//    SPI_IrqCmd(SPI_UNIT, SpiIrqReceive, Enable);
//    SPI_IrqCmd(SPI_UNIT, SpiIrqSend, Enable);

    //处于解码芯片工作状态下才启用DMA接收，启动阶段，直接用CPU读取SPI数据
    if (eStage == E_CHIP_WORK)
    {
        hd_spi_dma_init(); 
    }

    //for test
    while(1){
        /* Wait tx buffer empty */
        while (Reset == SPI_GetFlag(SPI_UNIT, SpiFlagSendBufferEmpty))
        {
        }
        Spi_WriteReadByte(0xAA);

        LOG_INFO("spi write a char \r\n");
        Ddl_Delay1ms(500);
    }

    //for test, remove me
    // PORT_ResetBits(SPI_NSS_PORT, SPI_NSS_PIN);
    // while (1)
    // {
    // }

    LOG_INFO("exit \r\n");
}

static void hd_spi_tx_cmplt_callback(void)
{ 
    if(Set == DMA_GetIrqFlag(SPI_DMA_UNIT,SPI_DMA_RX_CAHNNEL, TrnCpltIrq)){

        LOG_INFO("spi dma recv done \r\n");

        DMA_ClearIrqFlag(SPI_DMA_UNIT, SPI_DMA_RX_CAHNNEL, TrnCpltIrq);
        DMA_ChannelCmd(SPI_DMA_UNIT, SPI_DMA_RX_CAHNNEL,Disable);

        //通知数据处理线程，接收PINGPANG BUFFER中数据
//        extern asl_os_semaphore _semaphore_recv_new_frame;
//        asl_os_release_semaphore(_semaphore_recv_new_frame);
    }
}


void hd_spi_dma_init(){
    LOG_INFO("enter \r\n");

    stc_dma_config_t stcDmaCfg;
    MEM_ZERO_STRUCT(stcDmaCfg);

    /* Configuration peripheral clock */
    PWC_Fcg0PeriphClockCmd(SPI_DMA_CLOCK_UNIT, Enable);
    PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable);

    /* Configure TX DMA */
    stcDmaCfg.u16BlockSize = 1u;
    stcDmaCfg.u16TransferCnt = 1;
    stcDmaCfg.u32SrcAddr = (uint32_t)(&u8DummyByte);
    stcDmaCfg.u32DesAddr = (uint32_t)(&SPI_UNIT->DR);
    stcDmaCfg.stcDmaChCfg.enSrcInc = AddressFix;
    stcDmaCfg.stcDmaChCfg.enDesInc = AddressFix;
    stcDmaCfg.stcDmaChCfg.enTrnWidth = Dma8Bit;
    stcDmaCfg.stcDmaChCfg.enIntEn = Disable;
    DMA_InitChannel(SPI_DMA_UNIT, SPI_DMA_TX_CHANNEL, &stcDmaCfg);

    /* Configure RX DMA */
    stcDmaCfg.u16BlockSize = 1u;
    stcDmaCfg.u16TransferCnt = 1;
    stcDmaCfg.u32SrcAddr = (uint32_t)(&SPI_UNIT->DR);
    stcDmaCfg.u32DesAddr = (uint32_t)(&u8DummyByte);
    stcDmaCfg.stcDmaChCfg.enSrcInc = AddressFix;
    stcDmaCfg.stcDmaChCfg.enDesInc = AddressIncrease;
    stcDmaCfg.stcDmaChCfg.enTrnWidth = Dma8Bit;
    stcDmaCfg.stcDmaChCfg.enIntEn = Disable;
    DMA_InitChannel(SPI_DMA_UNIT, SPI_DMA_RX_CAHNNEL, &stcDmaCfg);

    //DMA数据接收完成中断注册
    stc_irq_regi_conf_t stcIrqRegiConf;
    MEM_ZERO_STRUCT(stcIrqRegiConf);
    stcIrqRegiConf.enIntSrc = SPI_DMA_RX_COMPLETE_SRC;
    stcIrqRegiConf.enIRQn = SPI3_RX_IRQn;
    stcIrqRegiConf.pfnCallback =  hd_spi_tx_cmplt_callback;
    enIrqRegistration(&stcIrqRegiConf);
    NVIC_SetPriority(stcIrqRegiConf.enIRQn, DDL_IRQ_PRIORITY_15);
    NVIC_ClearPendingIRQ(stcIrqRegiConf.enIRQn);
    NVIC_EnableIRQ(stcIrqRegiConf.enIRQn);//Enable Interrupt

    DMA_SetTriggerSrc(SPI_DMA_UNIT, SPI_DMA_TX_CHANNEL, SPI_DMA_TX_TRIG_SOURCE);
    DMA_SetTriggerSrc(SPI_DMA_UNIT, SPI_DMA_RX_CAHNNEL, SPI_DMA_RX_TRIG_SOURCE);

    DMA_Cmd(SPI_DMA_UNIT, Enable);

    LOG_INFO("exit \r\n");
}

void hd_spi_uninit(){
    SPI_UNIT->CR1_f.SPE = 0;
    SPI_UNIT->CR1_f.SPE = 1;

    //注：本质上，上面寄存器操作等价于下面两行
    // SPI_Cmd(SPI_DMA_UNIT, Disable);
    // SPI_Cmd(SPI_DMA_UNIT, Enable);
}

void set_dma_read_spi(unsigned int *rxBuffer, unsigned short dataLen){
    LOG("enter, dataLen = %d\r\n", dataLen);

    //DMA_SetSrcAddress(SPI_DMA_UNIT, SPI_DMA_TX_CHANNEL, (uint32_t)(&u8TxBuffer[0]));
    DMA_SetTransferCnt(SPI_DMA_UNIT, SPI_DMA_TX_CHANNEL, dataLen);

    DMA_SetDesAddress(SPI_DMA_UNIT, SPI_DMA_RX_CAHNNEL, (uint32_t)(&rxBuffer[0]));
    DMA_SetTransferCnt(SPI_DMA_UNIT, SPI_DMA_RX_CAHNNEL, dataLen);

    DMA_ClearIrqFlag(SPI_DMA_UNIT, SPI_DMA_TX_CHANNEL, TrnCpltIrq);
    DMA_ClearIrqFlag(SPI_DMA_UNIT, SPI_DMA_RX_CAHNNEL, TrnCpltIrq);

    DMA_ChannelCmd(SPI_DMA_UNIT, SPI_DMA_TX_CHANNEL, Enable);
    DMA_ChannelCmd(SPI_DMA_UNIT, SPI_DMA_RX_CAHNNEL, Enable);

    LOG_INFO("exit \r\n");
}